/* 
 * Copyright (C) 2001-2003 Jacek Sieka, j_s@telia.com
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#if !defined(AFX_USER_H__26AA222C_500B_4AD2_A5AA_A594E1A6D639__INCLUDED_)
#define AFX_USER_H__26AA222C_500B_4AD2_A5AA_A594E1A6D639__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "Util.h"
#include "Pointer.h"
#include "CriticalSection.h"
// CDM EXTENSION BEGINS
#include "TimerManager.h"
#include "StringTokenizer.h"
// CDM EXTENSION ENDS
class Client;
class FavoriteUser;

/**
 * A user connected to a hubs.
 */
class User : public PointerBase, public Flags
{
public:
	enum {
		OP_BIT,
		ONLINE_BIT,
		DCPLUSPLUS_BIT,
		PASSIVE_BIT,
		QUIT_HUB_BIT,
		LOST_LAST_BATTLE_BIT
		// CDM EXTENSION BEGINS
		,
		O_NICK_BIT,
		R_NICK_BIT
		// CDM EXTENSION ENDS
		// pothead starts svn119 , svn183
		, M_NICK_BIT
		, FAILED_ADLSEARCH_BIT
		// pothead ends
	};

	enum {
		OP = 1<<OP_BIT,
		ONLINE = 1<<ONLINE_BIT,
		DCPLUSPLUS = 1<<DCPLUSPLUS_BIT,
		PASSIVE = 1<<PASSIVE_BIT,
		QUIT_HUB = 1<<QUIT_HUB_BIT,
		LOST_LAST_BATTLE = 1<<LOST_LAST_BATTLE_BIT
		// CDM EXTENSION BEGINS
		,
		O_NICK = 1<<O_NICK_BIT,
		R_NICK = 1<<R_NICK_BIT
		// CDM EXTENSION ENDS
		// pothead starts svn119 , svn183
		, M_NICK = 1<<M_NICK_BIT
		, FAILED_ADLSEARCH = 1<<FAILED_ADLSEARCH_BIT
		// pothead ends
	};

	typedef Pointer<User> Ptr;
	typedef vector<Ptr> List;
	typedef List::iterator Iter;
	typedef HASH_MAP<string,Ptr> NickMap;
	typedef NickMap::iterator NickIter;

	struct HashFunction {
		static const size_t bucket_size = 4;
		static const size_t min_buckets = 8;
		size_t operator()(const Ptr& x) const { return ((size_t)(&(*x)))/sizeof(User); };
		bool operator()(const Ptr& a, const Ptr& b) const { return (&(*a)) < (&(*b)); };
	};

	User(const string& aNick) throw() : nick(aNick), bytesShared(0), client(NULL), favoriteUser(NULL), loggedIn(0)
	// CDM EXTENSION BEGINS
	, lastMyInfo(GET_TICK()), floodCounter(0)
	// CDM EXTENSION ENDS
	{ 
		// CDM EXTENSION BEGINS
		unCacheClientInfo();
		protectedUser = getProtected();
		// CDM EXTENSION ENDS
	};
	virtual ~User() throw();

	void setClient(Client* aClient);
	void connect();
	const string& getClientNick() const;
	const string& getClientName() const;
	string getClientAddressPort() const;
	string getClientRandomNick() const;
	void privateMessage(const string& aMsg);
	void clientMessage(const string& aMsg);
	void clientPM(const string& aTo, const string& aMsg);
	void clientSend(const string& aRaw);
	void kick(const string& aMsg);
	void redirect(const string& aTarget, const string& aReason);
	bool isClientOp() const;
	void send(const string& msg);

	string getFullNick() const { 
		string tmp(getNick());
		tmp += " (";
		tmp += getClientName();
		tmp += ")";
		return tmp;
	}
	
	void setBytesShared(const string& aSharing) { setBytesShared(Util::toInt64(aSharing)); };

	bool isOnline() const { return isSet(ONLINE); };
	bool isClient(Client* aClient) const { return client == aClient; };
	// CDM EXTENSION BEGINS
	//void getParams(StringMap& ucParams);
	void getParams(StringMap& ucParams, bool myNick = false);
	// CDM EXTENSION ENDS

	// favorite user stuff
	void setFavoriteUser(FavoriteUser* aUser);
	bool isFavoriteUser() const;
	bool getFavoriteGrantSlot() const;
	void setFavoriteGrantSlot(bool grant);
	void setFavoriteLastSeen(u_int32_t anOfflineTime = 0);
	u_int32_t getFavoriteLastSeen() const;
	const string& getUserDescription() const;
	void setUserDescription(const string& aDescription);

	static void updated(User::Ptr& aUser);
	
	GETSET(string, connection, Connection);
	GETSET(string, nick, Nick);
	GETSET(string, pk, Pk);
	GETSET(string, email, Email);
	GETSET(string, description, Description);
	GETSET(string, tag, Tag);
	GETSET(string, lastHubAddress, LastHubAddress);
	GETSET(string, lastHubName, LastHubName);
	GETSET(string, ip, Ip);
	GETSET(int64_t, bytesShared, BytesShared);
	// CDM EXTENSION BEGINS
	GETSET(string, lock, Lock);
	GETSET(string, host, Host);
	GETSET(string, supports, Supports);
	GETSET(string, clientType, ClientType);
	GETSET(string, previousLock, PreviousLock);
	GETSET(int64_t, downloadSpeed, DownloadSpeed);
	GETSET(int64_t, fileListSize, FileListSize);
	GETSET(int, iconStatus, IconStatus);
	GETSET(string, testSUR, TestSUR);
	GETSET(bool, hasTestSURinQueue, HasTestSURinQueue);
	const string& getUserIp() const { return userIp; };
	void setUserIp(const string& aIp);
	GETSET(string, isp, Isp);
	GETSET(string, unknownCommand, UnknownCommand);
	GETSET(int64_t, realShare, RealShare);
	GETSET(int, filesShared, FilesShared);
	GETSET(string, cheatingString, CheatingString);
	GETSET(string, smallFileResponse, SmallFileResponse);
	GETSET(int64_t, listLength, ListLength);
	GETSET(bool, testSURComplete, TestSURComplete);
	GETSET(bool, testSURoNickComplete, TestSURoNickComplete);
	GETSET(bool, testSURrNickComplete, TestSURrNickComplete);
	GETSET(bool, hasFilelistinQueue, HasFilelistinQueue);
	GETSET(bool, filelistComplete, FilelistComplete);
	GETSET(bool, badClient, BadClient);
	GETSET(bool, badFilelist, BadFilelist);
	GETSET(u_int32_t, fileListCheckedAt, FileListCheckedAt);
	GETSET(u_int32_t, testsurCheckedAt, TestsurCheckedAt);
	GETSET(string, knownHubsString, KnownHubsString);
	GETSET(int, connectedHubs, ConnectedHubs);
	GETSET(int, fileListDisconnects, FileListDisconnects);
	GETSET(int, connectionTimeouts, ConnectionTimeouts);
	GETSET(string, filelistGenerator, FilelistGenerator);
	GETSET(int, searchPort, SearchPort); 
	GETSET(int, hashedFilesShared, HashedFilesShared);
	GETSET(string, adlsComment, AdlsComment);
	GETSET(string, percentHashed, PercentHashed);
	GETSET(string, adlFile, AdlFile);
	GETSET(string, adlTTH, AdlTTH);
	GETSET(string, adlFileSize, AdlFileSize);
	GETSET(int64_t,	adlForbiddenSize, AdlForbiddenSize);
	//Sulan fix
	GETSET(string, clientComment, ClientComment);
	//Sulan start svn94
	GETSET(int, myinfos, Myinfos);
	GETSET(int64_t, loggedIn, LoggedIn);
	//Sulan start svn99
	GETSET(string, base, Base);
	GETSET(string, cid, Cid);
	//End
	// http://www.imperialnet.org/forum/viewtopic.php?t=1313
	// pothead starts svn119 , svn183 , svn189 , svn219 svn233 svn297
	GETSET(int, timeForTimeouts, TimeForTimeouts); 
	int getTimeForTimeouts() {
		return timeForTimeouts;
	}
	GETSET(bool, shouldRecheckFilelistBecauseOfADLSearch, ShouldRecheckFilelistBecauseOfADLSearch);
	GETSET(int, timeForFilelistRecheck, TimeForFilelistRecheck);
	int64_t getTimeForFilelistRecheck() {
		return timeForFilelistRecheck;
	}
	GETSET(bool, detectRMDC403D1, DetectRMDC403D1);
	GETSET(int, totalPoints, TotalPoints);
	GETSET(string, countryCode, CountryCode);
	GETSET(string, cheatFromProfiles, CheatFromProfiles);
	// pothead ends

	//Sulan start
	void checkFilelistGenerator(const string& listGen, const string& aCID, const string& aBase);
	//End
	string getTagVersion();
	bool getClaimsToBeDCPP() {
		return tag.find("<++ V:0.") != string::npos ? true : false;
	}
	
	// pothead starts svn189 (strongdc++ code)
	void rmDCDetect();
	// pothead ends

	void setCheat(const string& aCheatDescription, bool aBadClient, bool aBadFilelist);
	void sortCheatingString(const string& aCheatDescription, const bool adding);
	const string changeCheatingDescriptionsTokens();

	void setFileListShared(const int64_t aShareSize, const int aNumberOfFiles);
	bool CDMsCureCancerAndMakeYourDickBigger();
	Client* getClient() { return client; };
	string getReport();
	string loginTime;
	bool isCheckable(bool delay = true);
	bool shouldTestSUR() {
		return !hasTestSURinQueue && !testSURComplete;
	};
	bool shouldTestSURoNick() {
		if (Util::toFloat(getTagVersion()) >= 0.68 || getTag() == Util::emptyString)
			setTestSURoNickComplete();
		return !hasTestSURinQueue && testSURComplete && !testSURoNickComplete && !skipExtended;
	};
	bool shouldTestSURrNick() {
		if (!skipExtended) {
			return !hasTestSURinQueue && testSURComplete && testSURoNickComplete && !testSURrNickComplete && !skipExtended && !skipExtended2;
		} else {
			return !hasTestSURinQueue && testSURComplete && !testSURrNickComplete && !skipExtended2;
		}
	};
	bool shouldCheckFilelist(bool checkClients, bool extendedCheck1, bool extendedCheck2);
	void setIpAndHost(const string& aIp, const string& aHost) {
		ip = aIp;
		host = aHost;
		gotIp(false);
	};
	void setTestSURComplete();
	void setTestSURoNickComplete();
	void setTestSURrNickComplete();
	void setFilelistComplete();
	// pothead starts svn183
	void setShouldRecheckFilelistBecauseOfADLSearch();
	// pothead ends
	string getRawCommand(const int aRawCommand);
	void sendRawCommand(const int aRawCommand, const int context);
	void sendRawCommand(const string& aRawCommand, const int context, bool formatted = false);
	void unCacheClientInfo(bool all = true, bool putOffline = false) {
		if(!putOffline) {
			previousLock = Util::emptyString;
		}
		if(all) {
			iconStatus = 0;
			unsetFlag(User::M_NICK);
			unsetFlag(User::O_NICK);
			unsetFlag(User::R_NICK);
			hasTestSURinQueue = false;
			testSURComplete = false;
			testSURoNickComplete = false;
			testSURrNickComplete = false;
			hasFilelistinQueue = false;
			filelistComplete = false;
			loggedIn = GET_TICK();
			loginTime = Util::formatTime("%d-%m %H:%M", GET_TIME());
			userIp = Util::emptyString;
			//Sulan start svn94
			myinfos = 0;
			//End
			// pothead starts svn183 svn189
			shouldRecheckFilelistBecauseOfADLSearch = false;
			unsetFlag(User::FAILED_ADLSEARCH);
			detectRMDC403D1 = false;
			// pothead ends
		}
		pk = Util::emptyString;
		lock = Util::emptyString;
		host = Util::emptyString;
		supports = Util::emptyString;
		clientType = Util::emptyString;
		downloadSpeed = -1;
		fileListSize = -1;
		testSUR = Util::emptyString;
		unknownCommand = Util::emptyString;
		realShare = -1;
		filesShared = -1;
		cheatingString = Util::emptyString;
		smallFileResponse = Util::emptyString;
		listLength = -1;
		badClient = false;
		badFilelist = false;
		fileListCheckedAt = 0;
		testsurCheckedAt = 0;
		timeouts = 0;
		knownHubsString = Util::emptyString;
		connectedHubs = 1;
		fileListDisconnects = 0;
		connectionTimeouts = 0;
		filelistGenerator = Util::emptyString;
		searchPort = 0;
		hashedFilesShared = -1;
		badIsp = false;
		adlsComment = Util::emptyString;
		rechecked = false;
		skipExtended = false;
		skipExtended2 = false;
		percentHashed = Util::emptyString;
		//Sulan fix
		clientComment = Util::emptyString;
		//Sulan start svn99
		cid = Util::emptyString;
		base = Util::emptyString;
		//End
		// pothead starts svn119 , svn183 svn218 svn297 svn313
		timeForTimeouts = 0;
		timeForFilelistRecheck = 0;
		adlFile = Util::emptyString;
		adlFileSize = Util::emptyString;
		adlTTH = Util::emptyString;
		adlForbiddenSize = 0;
		totalPoints = 0;
		cheatFromProfiles = Util::emptyString;
		failedListlen11BWantRecheck = false;
		// pothead ends
	};
	void addLine(const string& aLine);
	void updated();
	bool isMyInfoSpamming();
	bool isProtected() const { return protectedUser; }
	const string& getTagSlots();
	// pothead starts svn195 svn313
	const string& getLimitSpeed();
	bool failedListlen11BWantRecheck;
	// pothead ends
	bool isHubCountFaking();
	string User::getHubs();
	string getNormalHubs();
	string getRegisteredHubs();
	string getOpHubs();
	int getTotalHubsAsInt();
	string getTotalHubs();
	void setFakeHubCounts(const int hubs, const string& hubString);
	bool fileListDisconnected();
	void connectionTimeout();
	void setPassive();
	void logDetect(bool successful);
	void setOp() {
		setFlag(OP);
		protectedUser = true;
	}
	void logRawCommand(const string& aRawCommand);
	bool isBadIsp() {
		return badIsp;
	}
	void setBadIsp(bool bad);
	bool shouldRecheck() {
		if(!rechecked) {
			rechecked = true;
			return true;
		}
		return false;
	}
	//Sulan start
	string getHisIp(){
		return userIp.empty() ? ip : userIp;
	}
	void setCountry();
	bool getProtected();
	bool getCountryCodeCheck();
	//Sulan start 29
	void displayCheat(const string& aLine);
	//End
	// CDM EXTENSION ENDS
	// pothead starts svn196 (sulan code)
	void myinfoDetect();
	// pothead ends
private:
	mutable RWLock cs;

	User(const User&);
	User& operator=(const User&);

	Client* client;
	FavoriteUser* favoriteUser;
	// CDM EXTENSION BEGINS
	void gotIp(bool uIp);

	bool protectedUser;
	bool badIsp;
	int floodCounter;
	int timeouts;
	u_int32_t lastMyInfo;
	string userIp;
	string tagSlots;
	bool rechecked;
	bool skipExtended;
	bool skipExtended2;
	// pothead starts svn195
	string limitSpeed;
	// pothead ends
	// CDM EXTENSION ENDS
};
#endif // !defined(AFX_USER_H__26AA222C_500B_4AD2_A5AA_A594E1A6D639__INCLUDED_)
/**
 * @file
 * $Id: User.h 334 2005-09-03 20:28:33Z Pothead $
 */